/*
 *
 *  * Copyright (c) 2016. For Intelligent Group.
 *
 */

package com.intelligent.ispc.r.analysis.spc;

import com.intelligent.ispc.r.analysis.RCommand;
import com.intelligent.ispc.r.dto.*;
import com.intelligent.ispc.r.utils.REnConnector;
import com.intelligent.ispc.r.utils.RUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by Peter on 2016/7/15.
 */
public class NDCommand implements RCommand {

    private AnalysisParamDto analysisParamDto;
    private String scriptPath;
    private int digitNum = 6;
    private NDConfiguration configuration;
    private NormalDistributionDto resultDto;

    /**
     * constructor
     * @param scriptPath r script path
     * */
    public NDCommand(String scriptPath) {
        this.scriptPath = scriptPath;
    }

    protected NormalDistributionDto buildScript() {
        digitNum = configuration.getDigitNum();
        REnConnector con = RUtils.getInstance().getConnector();
        int groupNum = analysisParamDto.getGroupNum();
        double[] dataAry = analysisParamDto.getAnalysisData();

        if ((dataAry == null) || (groupNum <= 0)) {
            return null;
        }
        NormalDistributionDto ndDto = new NormalDistributionDto();
        Integer tempDigitNum = analysisParamDto.getDigitNum();
//        if (tempDigitNum != null)
//            digitNum = tempDigitNum;

        con.setInput("x", dataAry);
        con.setInput("n", groupNum);
        con.setInput("bitNum", digitNum);
        con.execEval("source(\"" + scriptPath + "\")");


        double avgValue = con.getOutputDouble("avgValue");
        Double stdevValue = con.getOutputDouble("stdevValue");
        if (stdevValue.isNaN()) {
            stdevValue = 0D;
        }

        double minValue = con.getOutputDouble("minValue");
        double maxValue = con.getOutputDouble("maxValue");
        Double rangeValue = con.getOutputDouble("rangeValue");
        double[] curveXValue = con.getOutputDoubleArray("curveXValue");
        double[] curveYValue = con.getOutputDoubleArray("curveYValue");
        Double kurtosisValue = con.getOutputDouble("kurtosisValue");
        Double skewnessValue = con.getOutputDouble("skewnessValue");
        double[] divideValue = con.getOutputDoubleArray("divideValue");
        double[] barValue = con.getOutputDoubleArray("barValue");
        double[] clValue = con.getOutputDoubleArray("CL");
        double[] claDataValue = con.getOutputDoubleArray("moveClaData");
        while (con.isActive()) {
            con.disconnect();
        }
        RUtils.getSemaphore().release();


        Map<String, Object> otherAttribute = new HashMap<>();
        otherAttribute.put("claData", claDataValue);
        ndDto.setOtherAttribute(otherAttribute);

        NDStatisticsDto ndsDataItem = new NDStatisticsDto();
        ndsDataItem.setDataCount(analysisParamDto.getAnalysisData().length);
        ndsDataItem.setAvgValue(avgValue);
        ndsDataItem.setMinValue(minValue);
        ndsDataItem.setMaxValue(maxValue);
        ndsDataItem.setStdValue(stdevValue);
        ndsDataItem.setRangeValue(rangeValue.isNaN() ? 0D : rangeValue);
        ndsDataItem.setUclValue(avgValue + 3 * stdevValue);
        ndsDataItem.setLclValue(avgValue - 3 * stdevValue);
        ndsDataItem.setKurtosisValue(kurtosisValue.isNaN() ? 0D : kurtosisValue);
        ndsDataItem.setSkewnessValue(skewnessValue.isNaN() ? 0D : skewnessValue);
        ndsDataItem.setClValue(clValue);
        ndDto.setStatisticsDto(ndsDataItem);

        if ((curveYValue != null) && (curveYValue.length > 0)) {
            String str = String.valueOf(curveYValue[curveYValue.length - 1]);
            if (!"Infinity".equals(str)) {
                DefaultPlotDataDto normalCurveDto = new DefaultPlotDataDto();
                normalCurveDto.setX(curveXValue);
                normalCurveDto.setY(curveYValue);
                ndDto.setNormalCurveDto(normalCurveDto);
            }
        }
        DefaultPlotDataDto histogramDto = new DefaultPlotDataDto();
        histogramDto.setX(divideValue);
        histogramDto.setY(barValue);
        ndDto.setHistogramDto(histogramDto);

        ndDto.setPcData(getProcessCapabilityDto(avgValue, stdevValue));

        NDStandardDto ndStandardDto = new NDStandardDto();
        ndStandardDto.setGroupValue(analysisParamDto.getGroupNum());
        ndStandardDto.setCenterValue(analysisParamDto.getCenterValue());
        ndStandardDto.setLslValue(analysisParamDto.getLslValue());
        ndStandardDto.setUslValue(analysisParamDto.getUslValue());

        ndDto.setStandardDto(ndStandardDto);

        resultDto = ndDto;
        return ndDto;
    }

    @Override
    public void execute() {
        buildScript();
    }

    private ProcessCapabilityDto getProcessCapabilityDto(double avgValue, double sigmaValue) {
        ProcessCapabilityDto pcDataItem = new ProcessCapabilityDto();

        if (sigmaValue != 0) {
            Double iC = analysisParamDto.getCenterValue();
            Double iUSL = analysisParamDto.getUslValue();
            Double iLSL = analysisParamDto.getLslValue();
            if (iUSL == null || iLSL == null) {
                return pcDataItem;
            }

            double caValue = 0;
            if (!(iUSL > iLSL)) {
                return pcDataItem;
            } else {
                caValue = ((avgValue - iC) * 1.0) / ((iUSL - iLSL) / 2);
            }

            double cpuValue = (iUSL - avgValue) / (3 * sigmaValue);
            double cplValue = (avgValue - iLSL) / (3 * sigmaValue);
            double cpValue = (iUSL - iLSL) / (6 * sigmaValue);
            double cpkValue = (1 - Math.abs(caValue)) * cpValue;

            final int percentage = 100;
            pcDataItem.setCaData(new PCValueDto(caValue * percentage, configuration.getLevelTypeByCA(caValue * percentage)));
            pcDataItem.setCpuData(new PCValueDto(cpuValue, configuration.getLevelTypeByCPU(cpuValue)));
            pcDataItem.setCplData(new PCValueDto(cplValue, configuration.getLevelTypeByCPL(cplValue)));
            pcDataItem.setCpData(new PCValueDto(cpValue, configuration.getLevelTypeByCP(cpValue)));
            pcDataItem.setCpkData(new PCValueDto(cpkValue, configuration.getLevelTypeByCPK(cpkValue)));
        }

        return pcDataItem;
    }


    public AnalysisParamDto getAnalysisParamDto() {
        return analysisParamDto;
    }

    public void setAnalysisParamDto(AnalysisParamDto analysisParamDto) {
        this.analysisParamDto = analysisParamDto;
    }

    public void setConfiguration(NDConfiguration configuration) {
        this.configuration = configuration;
    }

    public NDConfiguration getConfiguration() {
        return configuration;
    }

    public NormalDistributionDto getResultDto() {
        return resultDto;
    }

    public void setResultDto(NormalDistributionDto resultDto) {
        this.resultDto = resultDto;
    }
}
